﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XSTDZ.ERP.Application.DataContracts;
using AutoMapper;
using XSTDZ.ERP.Domain.Models;
using XSTDZ.ERP.Core.Repositories;
using XSTDZ.ERP.Core.Generator;

namespace XSTDZ.ERP.Application.Implements
{
    public class ProductReturnBillServiceImpl : ApplicationServiceBase, IProductReturnBillService
    {
        IRepository<ProductReturnBill> _productReturnRepository;
        IRepository<ProductReturnBillDetail> _productReturnDetailRepository;
        IRepository<Stock> _stockRepository;
        IRepository<ReceivablePayableBill> _billReceRepository;
        public ProductReturnBillServiceImpl(IRepositoryContext repositoryContext,
            IRepository<ProductReturnBill> productReturnRepository,
             IRepository<ProductReturnBillDetail> productReturnDetailRepository,
            IRepository<Stock> stockRepository,
            IRepository<ReceivablePayableBill> billReceRepository
            )
            : base(repositoryContext)
        {
            this._productReturnRepository = productReturnRepository;
            this._productReturnDetailRepository = productReturnDetailRepository;
            this._stockRepository = stockRepository;
            this._billReceRepository = billReceRepository;
        }

        #region 审核
        
        
        public void Audit(IList<Guid> billIds, Guid auditId, Guid orgId)
        {

            var pinBills = this._productReturnRepository.GetAll(t => billIds.Contains(t.Id));
            var recelst = new List<ReceivablePayableBill>();
            pinBills.Each(t =>
            {
                t.AuditorID = auditId;
                t.AuditState = 1;
                t.AuditTime = DateTime.Now;
                recelst.Add(CreateReceivablePayableBill(t, auditId, orgId));
            });
            if (recelst != null && recelst.Count > 0)
            {
                ReceivablePayableServiceImpl rb = new ReceivablePayableServiceImpl(this.Context, this._billReceRepository, null);
                rb.CreateReceivablePayable(recelst);
            }
            this._productReturnRepository.Update(pinBills);
            this.Context.Commit();
        }
        private ReceivablePayableBill CreateReceivablePayableBill(ProductReturnBill sbill, Guid auditId, Guid orgId)
        {
            var bill = new ReceivablePayableBill();
            bill.ClientID = sbill.ClientID;
            bill.BillClassify = true;//付款
            bill.BillType = 1;//退货订单
            bill.BusinessID = sbill.Id;
            bill.CreateID = auditId;
            bill.OrgID = orgId;
            //总应收款
            bill.BillPayable = sbill.ProductReturnBillDetail.Where(t => t.Deleted == 0).Select(t => (decimal)((decimal)t.ReturnAmount * t.ReturnPrice)).Sum();
            return bill;
        }


        
        #endregion
        public Guid AddProductReturnBill(ProductReturnBillDto productReturnBillDto)
        {
            throw new NotImplementedException();
        }

        public Guid AddProductReturnBill(ProductReturnBillDto productReturnBillDto, IEnumerable<ProductReturnBillDetailDto> productReturnBillDetailDto)
        {
            var returnBill = Mapper.Map<ProductReturnBillDto, ProductReturnBill>(productReturnBillDto);
            var returnBillDetails = Mapper.Map<IEnumerable<ProductReturnBillDetailDto>, IEnumerable<ProductReturnBillDetail>>(productReturnBillDetailDto);
            returnBill.InitProductReturnBill().AddDetails(returnBillDetails);
            this._productReturnRepository.Add(returnBill);
            this.Context.Commit();
            return returnBill.Id;
        }

        public Guid AddProductReturnBill(Guid productReturnBillId, IEnumerable<ProductReturnBillDetailDto> productReturnBillDetailDto)
        {
            throw new NotImplementedException();
        }

        public void UpdateProductReturnBill(ProductReturnBillDto productReturnBillDto)
        {
            throw new NotImplementedException();
        }

        public void UpdateProductReturnBill(Guid productReturnBillId, IEnumerable<ProductReturnBillDetailDto> productReturnBillDetailDto)
        {
            throw new NotImplementedException();
        }

        public void UpdateProductReturnBill(ProductReturnBillDto productReturnBillDto, IEnumerable<ProductReturnBillDetailDto> productReturnBillDetailDto)
        {
            var returnBill = this._productReturnRepository.GetByKey(productReturnBillDto.Id);
            productReturnBillDto.CreateTime = returnBill.CreateTime;
            productReturnBillDto.CreateID = returnBill.CreateID;

            var targetBill = Mapper.Map(productReturnBillDto, returnBill);

            //处理明细
            var productCheckBillDetails = Mapper.Map<IEnumerable<ProductReturnBillDetailDto>, IEnumerable<ProductReturnBillDetail>>(productReturnBillDetailDto);

            var updateItems = new List<ProductReturnBillDetail>();
            var insertItems = new List<ProductReturnBillDetail>();
            var itemIds = returnBill.ProductReturnBillDetail.Select(d => d.Id).Cast<Guid>();

            productCheckBillDetails.Each(
                pd =>
                {
                    if (itemIds.Contains(pd.Id))
                    {
                        updateItems.Add(pd);
                    }
                    else
                    {
                        pd.ProductReturnBillID = returnBill.Id;
                        insertItems.Add(pd.InitProductReturnBillDetail());
                    }
                }
                );
            if (updateItems.Count() != 0)
            {
                foreach (var p in targetBill.ProductReturnBillDetail)
                {
                    foreach (var m in updateItems)
                    {
                        if (m.Id == p.Id)
                        {
                            p.StockID = m.StockID;
                            p.ReturnAmount = m.ReturnAmount;
                            p.ReturnPrice = m.ReturnPrice;
                            p.Remarks = m.Remarks;
                            break;
                        }
                    }
                }

                Mapper.Map(updateItems, targetBill.ProductReturnBillDetail);
            }
            if (insertItems.Count() != 0)
            {
                this._productReturnDetailRepository.Add(insertItems);
            }
            this._productReturnRepository.Update(targetBill);
            this.Context.Commit();
        }

        public void ConvertProductReturnBillDeleteState(Guid productReturnBillId)
        {
            var pbill = this._productReturnRepository.GetByKey(productReturnBillId);
            pbill.Deleted = 1;
            pbill.ProductReturnBillDetail.Each(d => { d.Deleted = 1; });
            this._productReturnRepository.Update(pbill);
            this.Context.Commit();
        }

        public void ConvertProductReturnBillDeleteState(Guid productReturnBillId, IEnumerable<Guid> productReturnDetailIds)
        {
            var pbill = this._productReturnRepository.GetByKey(productReturnBillId);
            pbill.ProductReturnBillDetail.Each(d =>
            {
                if (productReturnDetailIds.Contains(d.Id))
                {
                    d.Deleted = 1;
                }
            });
            this._productReturnRepository.Update(pbill);
            this.Context.Commit();
        }

        public ProductReturnBillDto GetProductReturnBill(Guid productReturnBillId)
        {
            var productCheckBill = this._productReturnRepository.GetByKey(productReturnBillId);
            if (productCheckBill.Auditor == null) { productCheckBill.Auditor = new User(); }
            if (productCheckBill.Client == null) { productCheckBill.Client = new ClientInfo(); }
            return Mapper.Map<ProductReturnBill, ProductReturnBillDto>(productCheckBill);
        }

        public IEnumerable<ProductReturnBillDto> GetProductReturnBills(int pageIndex, int pageSize)
        {
            var orderby = new OrderByParameter<ProductReturnBill>(m => m.CreateTime, SortOrder.Descending);
            var productCheckBills = this._productReturnRepository.GetAll(pageIndex, pageSize, new[] { orderby });
            // productCheckBills.Each(p => { if (p.Checkor == null) { p.Checkor = new User(); } });
            return Mapper.Map<IEnumerable<ProductReturnBill>, IEnumerable<ProductReturnBillDto>>(productCheckBills);
        }

        public void AddProductReturnBillDetail(Guid productInBillId, ProductReturnBillDetailDto productCheckBillDetailDto)
        {
            throw new NotImplementedException();
        }

        public void UpdateProductReturnBillDetail(Guid productInBillId, IEnumerable<ProductReturnBillDetailDto> productReturnBillDetailDto)
        {
            throw new NotImplementedException();
        }

        public ProductReturnBillDetailDto GetProductReturnBillDetail(Guid productCheckBillDetailId)
        {
            var productCheckBill = this._productReturnDetailRepository.GetByKey(productCheckBillDetailId);
            return Mapper.Map<ProductReturnBillDetail, ProductReturnBillDetailDto>(productCheckBill);
        }

        public IEnumerable<ProductReturnBillDetailDto> GetProductReturnBillDetails(Guid productReturnBillId)
        {
            var productCheckBills = this._productReturnDetailRepository.GetAll(d => d.ProductReturnBillID == productReturnBillId);
            return Mapper.Map<IEnumerable<ProductReturnBillDetail>, IEnumerable<ProductReturnBillDetailDto>>(productCheckBills);
        }

        public void Confirm(Guid billId)
        {
            var pinBills = this._productReturnRepository.GetByKey(billId);
            if (pinBills.BillState == 0)
            {
                pinBills.BillState = 1;
                UpdateToStock(pinBills);
                this._productReturnRepository.Update(pinBills);
                this.Context.Commit();
            }
        }

        private void UpdateToStock(ProductReturnBill pbill)
        {
            var updateStocks = new List<Stock>();
            pbill.ProductReturnBillDetail.Each(d =>
            {
                updateStocks.Add(new Stock
                {
                    Id = d.StockID,
                    StockCount = d.GetCount// d.ReturnAmount //退货数量  //实得数量只与库存有关，不产生账单
                });
            });
            if (updateStocks.Count() != 0)
            {
                StockServiceImpl stockServiceImpl = new StockServiceImpl(this.Context, this._stockRepository);
                stockServiceImpl.UpdateStockWithNoAdd(updateStocks);//更新库存
            }
        }

        public void UpdateToStock(Guid profitAndLossBillId, IEnumerable<Guid> profitAndLossBillDetailIds)
        {
            var updateStocks = new List<Stock>();
            var pbill = this._productReturnRepository.GetByKey(profitAndLossBillId);
            pbill.ProductReturnBillDetail.Each(d =>
            {
                if (profitAndLossBillDetailIds.Contains(d.Id))
                {
                    updateStocks.Add(new Stock
                    {
                        Id = d.StockID,
                        StockCount = d.ReturnAmount //退货数量
                    });
                }
            });
            if (updateStocks.Count() != 0)
            {
                StockServiceImpl stockServiceImpl = new StockServiceImpl(this.Context, this._stockRepository);
                stockServiceImpl.UpdateStockWithNoAdd(updateStocks);//更新库存
                this.Context.Commit();
            }
        }

        public void Audit(Guid profitAndLossBillId, Guid UserID)
        {
            var pbill = this._productReturnRepository.GetByKey(profitAndLossBillId);
            if (pbill.AuditState == 0)
            {
                pbill.AuditorID = UserID;
                pbill.AuditTime = DateTime.Now;
                pbill.AuditState = 1;
                _productReturnRepository.Update(pbill);
                this.Context.Commit();
            }
        }

        public string GetMaxBillNo()
        {
            var orderby = new OrderByParameter<ProductReturnBill>(m => m.CreateTime, SortOrder.Descending);
            var billNo = this._productReturnRepository.GetAll(1, 1, new[] { orderby }).FirstOrDefault();
            return billNo == null ? string.Empty : billNo.ReturnBillNo;
        }

        public Dictionary<ProductReturnBillDto, IEnumerable<ProductReturnBillDetailDto>> GetBillAndDetails(Guid outBillId)
        {
            var bill = this._productReturnRepository.GetByKey(outBillId);
            if (bill.Auditor == null) { bill.Auditor = new User(); }
            if (bill.Client == null) { bill.Client = new ClientInfo(); }
            var billDto = Mapper.Map<ProductReturnBill, ProductReturnBillDto>(bill);

            var billDetailDto = Mapper.Map<IEnumerable<ProductReturnBillDetail>, IEnumerable<ProductReturnBillDetailDto>>(bill.ProductReturnBillDetail.AsEnumerable());
            var result = new Dictionary<ProductReturnBillDto, IEnumerable<ProductReturnBillDetailDto>>();
            result.Add(billDto, billDetailDto);
            return result;
        }
    }

}
